﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeartLess.Managers;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using HeartLess.GameObjects;
using HeartLess.Core;

namespace HeartLess.Components
{
    public class ShockWave : CollidableGameObject, ShaderManager.IShaderDrawer
    {
        private Effect _waveEffect;
        private Texture2D _background;
        private RenderTarget2D _renderTarget;

        private float _currentRadius;
        private ShockWaveGun _gun;

        private const float MAX_RADIUS = 300;
        private const float SPEED = 600;

        private const string WAVE_TECHNIQUE = "Shockwave";
        private const string PARAM_SCREEN_SIZE = "gScreenSize";
        private const string PARAM_CENTER = "gCenter";
        private const string PARAM_INNER_RADIUS = "gInnerRadius";
        private const string PARAM_OUTER_RADIUS = "gOuterRadius";
        private const string PARAM_SOLID_WIDTH = "gSolidWidth";

        private static readonly Color _backgroundColor = new Color(233, 230, 255);

        public ShockWave(Vector2 location, ShockWaveGun gun)
            :base(location)
        {
            _gun = gun;
            _currentRadius = 0;

            _background = new Texture2D(HeartlessGame.Game.GraphicsDevice, 1, 1);
            Color[] color = { _backgroundColor };
            _background.SetData(color);

            _waveEffect = AssetManager.GetShader(AssetManager.SHADERS.SHOCKWAVE);
        }

        public override void Update(GameTime gameTime)
        {
            _currentRadius += SPEED * gameTime.ElapsedGameTime.Milliseconds / 1000;

            foreach (CollidableGameObject collidableObject in CollidableTriggers)
            {
                if (collidableObject is Player) continue;

                if (this.Intersects(collidableObject.Bounds))
                {
                    handleCollision(collidableObject);
                }
            }

            if (_currentRadius > MAX_RADIUS)
            {
                _gun.onFireDone();
            }
        }

        public void DrawShader(SpriteBatch spriteBatch, RenderTarget2D renderTarget)
        {
            Vector2 floatCoords = getCoords();

            _waveEffect.CurrentTechnique = _waveEffect.Techniques[WAVE_TECHNIQUE];
            _waveEffect.Parameters[PARAM_SCREEN_SIZE].SetValue(new Vector2(Screen.WINDOW_WIDTH, Screen.WINDOW_HEIGHT));
            _waveEffect.Parameters[PARAM_CENTER].SetValue(floatCoords);
            _waveEffect.Parameters[PARAM_INNER_RADIUS].SetValue(_currentRadius - 30f);
            _waveEffect.Parameters[PARAM_OUTER_RADIUS].SetValue(_currentRadius + 30f);
            _waveEffect.Parameters[PARAM_SOLID_WIDTH].SetValue(.06f);

            _waveEffect.CurrentTechnique.Passes[0].Apply();

            spriteBatch.Draw(_background,
                              Screen.WINDOW_BOUNDS,
                              null,
                              Color.White,
                              0f,
                              Vector2.Zero,
                              SpriteEffects.None,
                              0f);

            _renderTarget = renderTarget;
        }

        protected override void onMove()
        {
            //do nothing
        }

        private bool Intersects(Rectangle otherBounds)
        {

            Point circleDistance = new Point((int)Math.Abs(this.Bounds.X - otherBounds.X),
                                             (int)Math.Abs(this.Bounds.Y - otherBounds.Y));


            if (circleDistance.X > (otherBounds.Width / 2 + _currentRadius)) { return false; }
            if (circleDistance.Y > (otherBounds.Height / 2 + _currentRadius)) { return false; }

            if (circleDistance.X <= (otherBounds.Width / 2)) { return true; }
            if (circleDistance.Y <= (otherBounds.Height / 2)) { return true; }


            double cornerDistance_sq = Math.Pow(circleDistance.X - otherBounds.Width / 2 , 2) +
                                       Math.Pow(circleDistance.Y - otherBounds.Height / 2 , 2);

            return (cornerDistance_sq <= (Math.Pow(_currentRadius, 2)));
        }

        protected override void handleCollision(CollidableGameObject collidedObject)
        {
            if (collidedObject is Enemy)
            {
                Enemy enemy = collidedObject as Enemy;

                enemy.Kill();
            }
        }

        public override void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(_renderTarget,
                                Screen.WINDOW_BOUNDS,
                                null,
                                _backgroundColor,
                                0f,
                                Vector2.Zero,
                                SpriteEffects.None,
                                0f);
        }

        private Vector2 getCoords()
        {
            return (Location - Screen.CameraLocation)
                + new Vector2(LevelData.Level.UNIT_PIXEL_SIZE / 2.0f, LevelData.Level.UNIT_PIXEL_SIZE / 2.0f);

            // return new Vector2((relativePlayerCenter.X / Screen.CameraBounds.Width),
            //                     (relativePlayerCenter.Y / Screen.CameraBounds.Height));
        }

    }
}
